/*
 * Copyright (c) 2009, The MilkyTracker Team.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - Neither the name of the <ORGANIZATION> nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 *  XIInstrument.cpp
 *  MilkyPlay
 *
 *  Created by Peter Barth on 07.03.05.
 *
 */

#include "XIInstrument.h"

XIInstrument::XIInstrument () :
    owner(false)
{
    memset(&samples, 0, sizeof(samples));

    memset(sig, 0, sizeof(sig));
    memset(name, 0, sizeof(name));
    memset(tracker, 0, sizeof(tracker));
    memset(nbu, 0, sizeof(nbu));
    memset(&venv, 0, sizeof(venv));
    memset(&penv, 0, sizeof(penv));

    vibtype = vibsweep = vibdepth = vibrate = 0;
    volfade = 0;

    res = 0;

    memset(extra, 0, sizeof(extra));

    numsamples = 0;
}

XIInstrument::XIInstrument (const XIInstrument& source) :
    owner(true)
{
    memset(&samples, 0, sizeof(samples));

    memcpy(sig, source.sig, sizeof(sig));
    memcpy(name, source.name, sizeof(name));
    memcpy(tracker, source.tracker, sizeof(tracker));
    memcpy(nbu, source.nbu, sizeof(nbu));

    venv = source.venv;
    penv = source.penv;

    vibtype = source.vibtype;
    vibsweep = source.vibsweep;
    vibdepth = source.vibdepth;
    vibrate = source.vibrate;

    volfade = source.volfade;

    res = source.res;

    memcpy(extra, source.extra, sizeof(extra));

    numsamples = source.numsamples;

    for (mp_sint32 i = 0; i < numsamples; i++)
    {
        const TXMSample* src = &source.samples[i];
        TXMSample* dst = &samples[i];

        dst->samplen = src->samplen;
        dst->loopstart = src->loopstart;
        dst->looplen = src->looplen;
        dst->flags = src->flags;
        dst->vol = src->vol;
        dst->finetune = src->finetune;
        dst->type = src->type;
        dst->pan = src->pan;
        dst->relnote = src->relnote;
        dst->venvnum = src->venvnum;
        dst->penvnum = src->penvnum;
        dst->fenvnum = src->fenvnum;
        dst->vibenvnum = src->vibenvnum;
        dst->vibtype = src->vibtype;
        dst->vibsweep = src->vibsweep;
        dst->vibdepth = src->vibdepth;
        dst->vibrate = src->vibrate;
        dst->volfade = src->volfade;
        dst->res = src->res;

        memcpy(dst->name, src->name, sizeof(src->name));

        dst->terminate = src->terminate;

        if (src->sample)
        {
            if (src->type & 16)
            {
                dst->sample = (mp_sbyte*)(TXMSample::allocPaddedMem(src->samplen * 2));
                TXMSample::copyPaddedMem(dst->sample, src->sample, src->samplen * 2);
            }
            else
            {
                dst->sample = (mp_sbyte*)(TXMSample::allocPaddedMem(src->samplen));
                TXMSample::copyPaddedMem(dst->sample, src->sample, src->samplen);
            }
        }
    }

}

XIInstrument::~XIInstrument ()
{
    mp_sint32 numSamples = sizeof(samples) / sizeof(TXMSample);

    if (owner)
    {
        for (mp_sint32 i = 0; i < numSamples; i++)
            TXMSample::freePaddedMem((mp_ubyte*)samples[i].sample);
    }
}

void XIInstrument::clean()
{
    // find last used sample
    mp_sint32 numsmp = numsamples;
    mp_sint32 i;
    for (i = numsamples - 1; i >= 0; i--)
    {
        mp_ubyte buffer[MP_MAXTEXT + 1];

        XModule::convertStr(reinterpret_cast<char*>(buffer), reinterpret_cast<char*>(samples[i].name), MP_MAXTEXT, false);

        if (samples[i].sample || strlen(reinterpret_cast<char*>(buffer)))
        {
            numsmp = i + 1;
            break;
        }
    }
    if (i == -1)
        numsmp = 0;

    numsamples = numsmp;
}

mp_sint32 XIInstrument::load(const SYSCHAR* fileName)
{
    XMFile f(fileName);

    f.read(sig, 1, 21);

    if (memcmp(sig, "GF1PATCH", 8) == 0)
    {
        f.seek(0);
        return loadPAT(f);
    }

    if (memcmp(sig, "Extended Instrument: ", 21) != 0)
        return -8;

    f.read(name, 1, 22);

    if (f.readByte() != 0x1A)
        return -8;

    f.read(tracker, 1, 20);

    if (f.readWord() != 0x102)  // read version
        return -8;

    // read note instrument table
    f.read(nbu, 1, 96);
    mp_sint32 k;
    for (k = 0; k < 96; k++)
        if (nbu[k] > 15) nbu[k] = 15;

    // read envelopes
    memset(&venv, 0, sizeof(venv));
    memset(&penv, 0, sizeof(penv));

    for (k = 0; k < 12; k++)
    {
        venv.env[k][0] = f.readWord();
        venv.env[k][1] = f.readWord() << 2;
    }

    for (k = 0; k < 12; k++)
    {
        penv.env[k][0] = f.readWord();
        penv.env[k][1] = f.readWord() << 2;
    }

    // read envelope flags
    venv.num = f.readByte();
    penv.num = f.readByte();
    venv.sustain = f.readByte();
    venv.loops = f.readByte();
    venv.loope = f.readByte();
    penv.sustain = f.readByte();
    penv.loops = f.readByte();
    penv.loope = f.readByte();
    venv.type = f.readByte();
    penv.type = f.readByte();

    vibtype = f.readByte();
    vibsweep = f.readByte();
    vibdepth = f.readByte();
    vibrate = f.readByte();

    vibdepth <<= 1;

    volfade = f.readWord();

    volfade <<= 1;

    res = f.readWord();

    f.read(extra, 1, 20);

    numsamples = f.readWord();
    if (numsamples > 16)
        numsamples = 16;

    // read sample infos
    for (k = 0; k < numsamples; k++)
    {
        samples[k].samplen = f.readDword();
        samples[k].loopstart = f.readDword();
        samples[k].looplen = f.readDword();
        samples[k].vol = XModule::vol64to255(f.readByte());
        samples[k].finetune = f.readByte();
        samples[k].type = f.readByte();
        samples[k].pan = f.readByte();
        samples[k].relnote = f.readByte();
        samples[k].res = f.readByte();
        samples[k].volfade = volfade;
        samples[k].vibtype = vibtype;
        samples[k].vibsweep = vibsweep;
        samples[k].vibdepth = vibdepth;
        samples[k].vibrate = vibrate;
        f.read(samples[k].name, 1, 22);
    }

    // lazy guy
    TXMSample* smp = reinterpret_cast<TXMSample*>(&samples);

    // read samples
    for (k = 0; k < numsamples; k++)
    {
        if (!(smp[k].type & 16) && smp[k].samplen)
        {
            smp[k].sample = (mp_sbyte*)TXMSample::allocPaddedMem(smp[k].samplen);

            if (smp[k].sample == NULL)
            {
                return -7;
            }

            owner = true;

            if (!XModule::loadSample(f, smp[k].sample, smp[k].samplen, smp[k].samplen, XModule::ST_DELTA))
            {
                return -7;
            }
        }
        else if (smp[k].samplen)
        {
            smp[k].sample = (mp_sbyte*)TXMSample::allocPaddedMem(smp[k].samplen);

            if (smp[k].sample == NULL)
            {
                return -7;
            }

            owner = true;

            if (!XModule::loadSample(f, smp[k].sample, smp[k].samplen, smp[k].samplen >> 1, XModule::ST_DELTA | XModule::ST_16BIT))
            {
                return -7;
            }

            smp[k].samplen >>= 1;
            smp[k].loopstart >>= 1;
            smp[k].looplen >>= 1;
        }
    }

    return 0;
}

static mp_sint32 gusFreqToFT2Note(mp_dword freq)
{
    static const mp_dword scale_table[109] =
    {
        /*C-0..B-*/
        /* Octave 0 */ 16351, 17323, 18354, 19445, 20601, 21826, 23124, 24499, 25956, 27500, 29135, 30867,
        /* Octave 1 */ 32703, 34647, 36708, 38890, 41203, 43653, 46249, 48999, 51913, 54999, 58270, 61735,
        /* Octave 2 */ 65406, 69295, 73416, 77781, 82406, 87306, 92498, 97998, 103826, 109999, 116540, 123470,
        /* Octave 3 */ 130812, 138591, 146832, 155563, 164813, 174614, 184997, 195997, 207652, 219999, 233081, 246941,
        /* Octave 4 */ 261625, 277182, 293664, 311126, 329627, 349228, 369994, 391995, 415304, 440000, 466163, 493883,
        /* Octave 5 */ 523251, 554365, 587329, 622254, 659255, 698456, 739989, 783991, 830609, 880000, 932328, 987767,
        /* Octave 6 */ 1046503, 1108731, 1174660, 1244509, 1318511, 1396914, 1479979, 1567983, 1661220, 1760002, 1864657, 1975536,
        /* Octave 7 */ 2093007, 2217464, 2349321, 2489019, 2637024, 2793830, 2959960, 3135968, 3322443, 3520006, 3729316, 3951073,
        /* Octave 8 */ 4186073, 4434930, 4698645, 4978041, 5274051, 5587663, 5919922, 6271939, 6644889, 7040015, 7458636, 7902150, 0xFFFFFFFF
    };

    for (mp_uint32 no = 0; no < sizeof(scale_table) / sizeof(mp_dword) - 1; no++)
    {
        if (scale_table[no] <= freq &&
            scale_table[no + 1] >= freq)
            return (no - 12);
    }

    return 4 * 12;
}

#define PAT_CLEAN \
    for (mp_uint32 j = 0; j < sizeof(nbu); j++) \
        if (nbu[j] == 0xFF) nbu[j] = 0;

mp_sint32 XIInstrument::loadPAT(XMFile& f)
{

    struct TGF1PatchHeader
    {
        mp_ubyte sig[22];
        mp_ubyte desc[60];
        mp_ubyte insnum;
        mp_ubyte voicenum;
        mp_ubyte channum;
        mp_uword waveforms;
        mp_uword mastervol;
        mp_uint32 datasize;
        mp_ubyte reserved1[36];
        mp_uword insID;
        mp_ubyte insname[16];
        mp_uint32 inssize;
        mp_ubyte layers;
        mp_ubyte reserved2[40];
        mp_ubyte layerduplicate;
        mp_ubyte layer;
        mp_uint32 layersize;
        mp_ubyte smpnum;
        mp_ubyte reserved3[40];
    };

    struct TGF1PatchSampleHeader
    {
        mp_ubyte wavename[7];
        mp_ubyte fractions;
        mp_uint32 samplesize;
        mp_sint32 loopstart;
        mp_sint32 loopend;
        mp_uword samplerate;
        mp_uint32 lofreq;
        mp_uint32 hifreq;
        mp_uint32 rtfreq;
        mp_uword tune;
        mp_ubyte panning;

        mp_ubyte envelopes[4 * 3];
        mp_ubyte tremolo[3];
        mp_ubyte vibrato[3];

        mp_ubyte smpmode;
        mp_uword scalefreq;
        mp_uword scalefac;
        mp_ubyte reserved[36];
    };

    TGF1PatchHeader header;

    f.read(header.sig, 1, 22);
    f.read(header.desc, 1, 60);
    header.insnum = f.readByte();
    header.voicenum = f.readByte();
    header.channum = f.readByte();
    header.waveforms = f.readWord();
    header.mastervol = f.readWord();
    header.datasize = f.readDword();
    f.read(header.reserved1, 1, 36);
    header.insID = f.readWord();
    f.read(header.insname, 1, 16);
    header.inssize = f.readDword();
    header.layers = f.readByte();
    f.read(header.reserved2, 1, 40);
    header.layerduplicate = f.readByte();
    header.layer = f.readByte();
    header.layersize = f.readDword();
    header.smpnum = f.readByte();
    f.read(header.reserved3, 1, 40);

    // apply data
    memcpy(name, header.insname, 16);
    numsamples = header.smpnum <= 16 ? header.smpnum : 16;

    // lazy guy
    TXMSample* smp = reinterpret_cast<TXMSample*>(&samples);

    memset(nbu, 0xFF, sizeof(nbu));

    for (mp_sint32 i = 0; i < numsamples; i++)
    {
        TGF1PatchSampleHeader smphdr;

        f.read(smphdr.wavename, 1, 7);
        smphdr.fractions = f.readByte();
        smphdr.samplesize = f.readDword();
        smphdr.loopstart = f.readDword();
        smphdr.loopend = f.readDword();
        smphdr.samplerate = f.readWord();
        smphdr.lofreq = f.readDword();
        smphdr.hifreq = f.readDword();
        smphdr.rtfreq = f.readDword();

        mp_sint32 lo = gusFreqToFT2Note(smphdr.lofreq);
        mp_sint32 hi = gusFreqToFT2Note(smphdr.hifreq);

        if (lo < 0)
            lo = 0;
        if (hi < 0)
            hi = 0;
        if (lo > 95)
            lo = 95;
        if (hi > 95)
            hi = 95;

        // sanity check
        if (lo > hi)
        {
            mp_sint32 s = lo;
            lo = hi;
            hi = s;
        }

        //if (i == numsamples - 1)
        //	hi = 96;

        for (mp_sint32 j = lo; j < hi; j++)
            if (j >= 0 && j <= 95)
                if (nbu[j] == 0xFF) nbu[j] = i;

        //ld(x) = log(x)/log(2)

        #ifdef VERBOSE
        printf("%i:\nlo:%i,hi:%i,rt:%i,%i:%i\n", i, smphdr.lofreq, smphdr.hifreq, smphdr.rtfreq, lo, hi);
        #endif
        smphdr.tune = f.readWord();
        smphdr.panning = f.readByte();
        f.read(smphdr.envelopes, 3, 4);
        f.read(smphdr.tremolo, 1, 3);
        f.read(smphdr.vibrato, 1, 3);
        smphdr.smpmode = f.readByte();
        smphdr.scalefreq = f.readWord();
        smphdr.scalefac = f.readWord();
        f.read(smphdr.reserved, 1, 36);

        samples[i].samplen = smphdr.samplesize;
        samples[i].loopstart = smphdr.loopstart;
        samples[i].looplen = smphdr.loopend - smphdr.loopstart;
        // disable looping on invalid loop range
        if ((mp_sint32)samples[i].looplen < 0)
        {
            samples[i].looplen = 0;
            smphdr.smpmode &= ~(1 << 2);
        }
        samples[i].vol = XModule::vol127to255(header.mastervol);
        samples[i].pan = (mp_ubyte) XModule::pan15to255(smphdr.panning);

        #if 1
        mp_sint32 no = gusFreqToFT2Note(smphdr.rtfreq);
        no -= 48;

        //mp_sint32 rate = XModule::getc4spd(no, 0);
        XModule::convertc4spd(smphdr.samplerate /**rate/8363*/, &samples[i].finetune, &samples[i].relnote);

        mp_sint32 relnote = (mp_sint32)samples[i].relnote - no;
        // validate note range
        if (relnote < -96) relnote = -96;
        if (relnote > 95) relnote = 95;

        samples[i].relnote = relnote;
        #else
        XModule::convertc4spd(smphdr.samplerate, &samples[i].finetune, &samples[i].relnote);
        #endif

        // 16 bit sample
        if (smphdr.smpmode & 1)
        {
            samples[i].type = 16;
        }
        // looping
        if (smphdr.smpmode & 4) samples[i].type |= 1;
        // bi-loop
        if (smphdr.smpmode & 8)
        {
            samples[i].type &= ~3;
            samples[i].type |= 2;
        }

        memcpy(samples[i].name, smphdr.wavename, 7);

        if (!(smp[i].type & 16) && smp[i].samplen)
        {
            smp[i].sample = (mp_sbyte*)TXMSample::allocPaddedMem(smp[i].samplen);

            if (smp[i].sample == NULL)
            {
                PAT_CLEAN;
                return -7;
            }

            owner = true;

            if (smphdr.smpmode & 2)
            {
                if (!XModule::loadSample(f, smp[i].sample, smp[i].samplen, smp[i].samplen, XModule::ST_UNSIGNED))
                {
                    PAT_CLEAN;
                    return -7;
                }
            }
            else
            {
                if (!XModule::loadSample(f, smp[i].sample, smp[i].samplen, smp[i].samplen))
                {
                    PAT_CLEAN;
                    return -7;
                }
            }
        }
        else if (smp[i].samplen)
        {
            smp[i].sample = (mp_sbyte*)TXMSample::allocPaddedMem(smp[i].samplen);

            if (smp[i].sample == NULL)
            {
                PAT_CLEAN;
                return -7;
            }

            owner = true;

            if (smphdr.smpmode & 2)
            {
                if (!XModule::loadSample(f, smp[i].sample, smp[i].samplen, smp[i].samplen >> 1, XModule::ST_16BIT | XModule::ST_UNSIGNED))
                {
                    PAT_CLEAN;
                    return -7;
                }
            }
            else
            {
                if (!XModule::loadSample(f, smp[i].sample, smp[i].samplen, smp[i].samplen >> 1, XModule::ST_16BIT))
                {
                    PAT_CLEAN;
                    return -7;
                }
            }

            smp[i].samplen >>= 1;
            smp[i].loopstart >>= 1;
            smp[i].looplen >>= 1;
        }

    }

    PAT_CLEAN;

    return 0;
}

mp_sint32 XIInstrument::save(const SYSCHAR* fileName)
{
    clean();

    XMFile f(fileName, true);

    f.write("Extended Instrument: ", 1, 21);

    f.write(name, 1, 22);

    f.writeByte(0x1A);

    f.write("FastTracker v2.00   ", 1, 20);

    f.writeWord(0x102);

    f.write(nbu, 1, 96);

    mp_sint32 k;
    for (k = 0; k < 12; k++)
    {
        f.writeWord(venv.env[k][0]);
        f.writeWord(venv.env[k][1] >> 2);
    }

    for (k = 0; k < 12; k++)
    {
        f.writeWord(penv.env[k][0]);
        f.writeWord(penv.env[k][1] >> 2);
    }

    // read envelope flags
    f.writeByte(venv.num);
    f.writeByte(penv.num);
    f.writeByte(venv.sustain);
    f.writeByte(venv.loops);
    f.writeByte(venv.loope);
    f.writeByte(penv.sustain);
    f.writeByte(penv.loops);
    f.writeByte(penv.loope);
    f.writeByte(venv.type);
    f.writeByte(penv.type);

    f.writeByte(vibtype);
    f.writeByte(vibsweep);
    f.writeByte(vibdepth >> 1);
    f.writeByte(vibrate);

    f.writeWord(volfade >> 1);

    f.writeWord(0);

    memset(extra, 0, sizeof(extra));
    f.write(extra, 1, 20);

    f.writeWord(numsamples);

    // read sample infos
    for (k = 0; k < numsamples; k++)
    {
        if (samples[k].type & 16)
        {
            f.writeDword(samples[k].samplen << 1);
            f.writeDword(samples[k].loopstart << 1);
            f.writeDword(samples[k].looplen << 1);
        }
        else
        {
            f.writeDword(samples[k].samplen);
            f.writeDword(samples[k].loopstart);
            f.writeDword(samples[k].looplen);
        }
        f.writeByte(samples[k].vol * 64 / 255);
        f.writeByte(samples[k].finetune);
        f.writeByte(samples[k].type);
        f.writeByte(samples[k].pan);
        f.writeByte(samples[k].relnote);
        f.writeByte(samples[k].res);
        f.write(samples[k].name, 1, 22);
    }

    // lazy guy
    TXMSample* smp = reinterpret_cast<TXMSample*>(&samples);

    // write samples
    for (k = 0; k < numsamples; k++)
    {
        if ((smp[k].type & 16) && smp[k].samplen && smp[k].sample)
        {
            mp_sword* dst = new mp_sword[smp[k].samplen];

            mp_sword last = 0;
            for (mp_uint32 i = 0; i < smp[k].samplen; i++)
            {
                dst[i] = smp[k].getSampleValue(i) - last;
                last = smp[k].getSampleValue(i);
            }

            f.writeWords((mp_uword*)dst, smp[k].samplen);

            delete[] dst;
        }
        else if (smp[k].samplen && smp[k].sample)
        {
            mp_sbyte* dst = new mp_sbyte[smp[k].samplen];

            mp_sbyte last = 0;
            for (mp_uint32 i = 0; i < smp[k].samplen; i++)
            {
                dst[i] = smp[k].getSampleValue(i) - last;
                last = smp[k].getSampleValue(i);
            }

            f.write(dst, 1, smp[k].samplen);

            delete[] dst;
        }
    }

    return 0;
}

XIInstrument& XIInstrument::operator =(const XIInstrument& source)
{
    // no self-assignment
    if (this != &source)
    {
        // free up whatever is in there
        if (owner)
        {
            mp_sint32 numSamples = sizeof(samples) / sizeof(TXMSample);
            for (mp_sint32 i = 0; i < numSamples; i++)
                TXMSample::freePaddedMem((mp_ubyte*)samples[i].sample);
        }

        memset(&samples, 0, sizeof(samples));

        // owner is now true
        owner = true;

        // copy
        memcpy(sig, source.sig, sizeof(sig));
        memcpy(name, source.name, sizeof(name));
        memcpy(tracker, source.tracker, sizeof(tracker));
        memcpy(nbu, source.nbu, sizeof(nbu));

        venv = source.venv;
        penv = source.penv;

        vibtype = source.vibtype;
        vibsweep = source.vibsweep;
        vibdepth = source.vibdepth;
        vibrate = source.vibrate;

        volfade = source.volfade;

        res = source.res;

        memcpy(extra, source.extra, sizeof(extra));

        numsamples = source.numsamples;

        for (mp_sint32 i = 0; i < numsamples; i++)
        {
            const TXMSample* src = &source.samples[i];
            TXMSample* dst = &samples[i];

            dst->samplen = src->samplen;
            dst->loopstart = src->loopstart;
            dst->looplen = src->looplen;
            dst->flags = src->flags;
            dst->vol = src->vol;
            dst->finetune = src->finetune;
            dst->type = src->type;
            dst->pan = src->pan;
            dst->relnote = src->relnote;
            dst->venvnum = src->venvnum;
            dst->penvnum = src->penvnum;
            dst->fenvnum = src->fenvnum;
            dst->vibenvnum = src->vibenvnum;
            dst->vibtype = src->vibtype;
            dst->vibsweep = src->vibsweep;
            dst->vibdepth = src->vibdepth;
            dst->vibrate = src->vibrate;
            dst->volfade = src->volfade;
            dst->res = src->res;

            memcpy(dst->name, src->name, sizeof(src->name));

            dst->terminate = src->terminate;

            if (src->sample)
            {
                if (src->type & 16)
                {
                    dst->sample = (mp_sbyte*)(TXMSample::allocPaddedMem(src->samplen * 2));
                    TXMSample::copyPaddedMem(dst->sample, src->sample, src->samplen * 2);
                }
                else
                {
                    dst->sample = (mp_sbyte*)(TXMSample::allocPaddedMem(src->samplen));
                    TXMSample::copyPaddedMem(dst->sample, src->sample, src->samplen);
                }
            }
        }
    }

    return *this;
}